﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Modbus.Device;
using System.IO.Ports;
using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;
namespace MonitorModule.Services {


    public class ModbusHeartbeat {
        private IModbusSerialMaster _master;
        private SerialPort _serialPort;
        private Timer _heartbeatTimer;
        /// <summary>
        /// 从站地址
        /// </summary>
        private byte _slaveId = 1;
        /// <summary>
        /// 心跳寄存器地址
        /// </summary>
        private ushort _heartbeatReg = 40001;
        /// <summary>
        ///  心跳周期(ms)
        /// </summary>
        private const int HeartbeatInterval = 2000;
        /// <summary>
        /// 复位指令（避免与正常自增值冲突）
        /// </summary>
        private const ushort ResetCommand = 0xAAAA; 

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="comPort"></param>
        public void Start(string comPort) {
            // 初始化串口
            _serialPort = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
            _serialPort.Open();

            // 创建 Modbus RTU 主站
            _master = ModbusSerialMaster.CreateRtu(_serialPort);

            // 心跳定时器
            _heartbeatTimer = new Timer(HeartbeatInterval);
            _heartbeatTimer.Elapsed += CheckHeartbeat;
            _heartbeatTimer.AutoReset = true;
            _heartbeatTimer.Start();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void CheckHeartbeat(object sender, ElapsedEventArgs e) {
            try {
                // 阶段1：读取当前值 V1
                ushort v1 = _master.ReadHoldingRegisters(_slaveId, _heartbeatReg, 1)[0];

                // 阶段2：写入复位指令 (0xAAAA)
                _master.WriteSingleRegister(_slaveId, _heartbeatReg, ResetCommand);

                // 等待复位生效（根据从机响应速度调整）
                await Task.Delay(150);

                // 阶段3：读取复位后值 V2
                ushort v2 = _master.ReadHoldingRegisters(_slaveId, _heartbeatReg, 1)[0];

                // 验证逻辑（需从机配合：收到0xAAAA后立即复位计数器）
                bool isAlive = v2 > 0 && v2 < 10; // 假设从机150ms内自增<10

                if (!isAlive) {
                    throw new Exception($"心跳丢失! 复位前:{v1} 复位后:{v2}");
                }
            } catch (Exception ex) {
                // 异常处理（重连/告警）
                Reconnect();
                Console.WriteLine($"心跳异常: {ex.Message}");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        private void Reconnect() {
            _master?.Dispose();
            _serialPort?.Close();
            Thread.Sleep(1000);
            Start("COM1"); // 重新初始化
        }
    }
}
